package com.shigu.wxpaysdk.common;

import com.shigu.wxpaysdk.request.PayRequest;
import com.shigu.wxpaysdk.response.PayResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * Created by wxc on 2016/12/13.
 *
 * @author wxc
 * @version wxpaysdk 0.0.1
 * @since wxpaysdk 0.0.1
 */
public class Signature {

    private static final Logger logger = LoggerFactory.getLogger(Signature.class);

    private static String toMD5(String plainText) {
        //生成实现指定摘要算法的 MessageDigest 对象。
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            logger.warn("get MD5 digest error!", e);
            return "";
        }
        //使用指定的字节数组更新摘要。
        md.update(plainText.getBytes());
        //通过执行诸如填充之类的最终操作完成哈希计算。
        byte b[] = md.digest();
        //生成具体的md5密码到buf数组
        StringBuilder sb = new StringBuilder("");
        for (int i : b) {
            if (i < 0)
                i += 256;
            if (i < 16)
                sb.append("0");
            sb.append(Integer.toHexString(i));
        }
//        System.out.println("16位: " + buf.toString().substring(8, 24));// 16位的加密，其实就是32位加密后的截取
        return sb.toString();
    }

    /**
     * 获取一定长度的随机字符串
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String nonceStr(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static void sign(PayRequest request) {
        request.setAppid(Configure.appid);
        request.setMch_id(Configure.mch_id);
        request.setNonce_str(nonceStr(32));
        request.setSign(getSign(request));
    }
    public static String getSign(Object o) {
        Class requestClass = o.getClass();
        Field[] declaredFields = requestClass.getSuperclass().getDeclaredFields();
        Field[] fields = requestClass.getDeclaredFields();
        List<Field> fieldList = new ArrayList<>(declaredFields.length + fields.length);
        fieldList.addAll(Arrays.asList(declaredFields));
        fieldList.addAll(Arrays.asList(fields));
        List<String> params = new ArrayList<>(fieldList.size());
        for (Field field : fieldList) {
            field.setAccessible(true);
            Object v = null;
            try {
                v = field.get(o);
            } catch (IllegalAccessException e) {
                logger.warn("get param error!" , e);
            }
            String name = field.getName();
            if (v != null && !"sign".equals(name))
                params.add(name + "=" + v + "&");
        }
        Collections.sort(params);
        logger.info("Params:" + params);
        StringBuilder sb = new StringBuilder();
        for (String param : params)
            sb.append(param);
        sb.append("key=");
        if (Configure.test)
            sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ123456");
        else
            sb.append(Configure.key);
        return toMD5(sb.toString()).toUpperCase();
    }

    public static boolean check(Object obj) {
        if (obj == null) return true;
        PayResponse o = (PayResponse) obj;
        return !"SUCCESS".equals(o.getReturn_code()) || o.getSign() != null && o.getSign().equals(getSign(o));
    }

}
